package com.lf.jwt2admin;

import com.lf.constant.ConstantsValue;
import com.lf.enums.ErrorCodeEnum;
import com.lf.exception.ApiException;
import com.lf.jwt.ITokenManager;
import com.lf.jwt.JwtUtil;
import com.lf.jwt.TokenEntity;
import com.lf.mapper.MapperList;
import com.lf.redis.IRedisService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* @ClassName: RedisTokenManager
* @Description:  通过Redis存储和验证token的实现类
* @Author: bite
* @Date: 2019/3/11
*/
@Slf4j
@Component
public class RedisTokenAdmin implements ITokenAdmin {


    @Autowired
    protected JwtUtil jwtUtil;


    @Autowired
    protected IRedisService redisService;
    /**
     * 生成TOKEN
     *
     * @param userId
     * @param account
     * @param claims
     * @return
     */
    @Override
    public TokenEntity createToken(Integer userId, String account, Map<String, Object> claims) {
        try {
            long ttlMillis = ConstantsValue.TOKEN_EXPIRES_HOUR_10 * 1000L;
            String token = jwtUtil.createJWT(userId, account, claims, ttlMillis);
            TokenEntity model = new TokenEntity(token, jwtUtil.parseJWT(token));
            String key = ConstantsValue.TOKEN_MANAGER_KEY  + userId;
            //存储到redis并设置过期时间
            redisService.setString(key, token, ConstantsValue.TOKEN_EXPIRES_HOUR_10, TimeUnit.SECONDS);
            return model;
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
            throw new ApiException(ErrorCodeEnum.TK1003);
        }
    }

    /**
     * TOKEN解密
     *
     * @param authentication 加密后的字符串
     * @return
     */
    @Override
    public TokenEntity getToken(String authentication) throws ApiException, ExpiredJwtException {
        try {

            if (StringUtils.isEmpty(authentication)) {
                return null;
            }

            Claims claims = jwtUtil.parseJWT(authentication);

            TokenEntity tokenEntity = new TokenEntity(authentication, claims);

            return tokenEntity;
        }catch (ExpiredJwtException ee){
            throw ee;
        }catch (Exception e) {
            throw new ApiException(ErrorCodeEnum.TK1002);
        }
    }


    /**
     * 检查token是否有效
     *
     * @param model token
     * @return
     */
    @Override
    public ErrorCodeEnum checkToken(TokenEntity model) {
        if (model == null) {
            return ErrorCodeEnum.TK1009;
        }
        String key = ConstantsValue.TOKEN_MANAGER_KEY  + model.getUserId();
        String token = null;
        try{
            token = redisService.getString(key);
        }catch (Exception e){
           throw new ApiException(ErrorCodeEnum.FL501);
        }
        //没有从redis获取到token,则直接返回 token不存在
        if (StringUtils.isBlank(token)){
            return ErrorCodeEnum.TK1009;
        }
        //传递过的token值必须和redis中的token值
        if (!model.getToken().equalsIgnoreCase(token)) {
            //Redis不存在说明 Token已过期
            return ErrorCodeEnum.TK1005;
        }

        try {
            //JWT相关验证
            if (StringUtils.isNotBlank(token)) {
                Claims claims = jwtUtil.parseJWT(token);
//                System.out.println(model.getUserId()+", "+claims.getId());
                if (!claims.getId().equals(model.getUserId().toString())) {
                    return ErrorCodeEnum.TK1002;
                }

                if (!claims.getIssuer().equals(ConstantsValue.JWT_ISSUER)) {
                    return ErrorCodeEnum.TK1002;
                }
            } else {
                return ErrorCodeEnum.TK1009;
            }

        } catch (Exception e) {
            return ErrorCodeEnum.TK1007;
        }
        // 刷新redis中token有效期(不使用,原因: JWT创建token就是要设置Expiration,所以只刷新redis并没用)
        //redisHelper.expireKey(key, ConstantInterface.TOKEN_EXPIRES_HOUR, TimeUnit.SECONDS);
        return ErrorCodeEnum.SC0;
    }


    /**
     * 清除TOKEN
     *
     * @param userId 登录用户的id
     */
    @Override
    public void deleteToken(Integer userId) {
        redisService.deleteString(ConstantsValue.TOKEN_MANAGER_KEY + userId);
    }


}
